2 * Copyright (c) 2017-2019 Apple Inc. All rights reserved.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 #include "unittest_common.h"
18 #import <XCTest/XCTest.h>
20 struct UDPSocket_struct
22 mDNSIPPort port; // MUST BE FIRST FIELD -- mDNSCoreReceive expects every UDPSocket_struct to begin with mDNSIPPort port
24 typedef struct UDPSocket_struct UDPSocket;
26 // This client request was generated using the following command: "dns-sd -Q web.mydomain.test".
27 uint8_t test_order_query_msgbuf[30] = {
28 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x65, 0x62, 0x2e, 0x6d, 0x79, 0x64,
29 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x00, 0x00, 0x01, 0x00, 0x01
32 0000 10 c1 01 00 00 01 00 00 00 00 00 00 03 77 65 62
33 0010 08 6d 79 64 6f 6d 61 69 6e 04 74 65 73 74 00 00
36 0000 ef 53 01 00 00 01 00 00 00 00 00 00 03 77 65 62
37 0010 08 6d 79 64 6f 6d 61 69 6e 04 74 65 73 74 00 00
40 uint8_t test_query_client_msgbuf[35] = {
41 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x31, 0x32, 0x33, 0x73, 0x65, 0x72, 0x76, 0x65,
42 0x72, 0x2e, 0x64, 0x6f, 0x74, 0x62, 0x65, 0x6e, 0x6e, 0x75, 0x2e, 0x63, 0x6f, 0x6d, 0x00, 0x00,
46 // This uDNS message is a canned response that was originally captured by wireshark.
47 uint8_t test_order_response1_msgbuf[228] = {
48 0x0f, 0x98, // transaction id
50 0x00, 0x01, // 1 query: web.mydomain.test: type A, class IN
51 0x00, 0x04, // 4 anwsers: Addr 10.0.0.101, Addr 10.0.0.105, Addr 10.0.0.104, Addr 10.0.0.102
52 0x00, 0x01, // 1 authoritative nameservers: mydomain.test: type NS, class IN, ns ns.mydomain.test
53 0x00, 0x01, // 1 additional: ns.mydomain.test: type A, class IN, addr 192.168.0.23
54 0x03, 0x77, 0x65, 0x62,
55 0x08, 0x6d, 0x79, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x04, 0x74, 0x65, 0x73, 0x74, 0x00, 0x00,
56 0x01, 0x00, 0x01, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x0a,
57 0x00, 0x00, 0x65, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x0a,
58 0x00, 0x00, 0x69, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x0a,
59 0x00, 0x00, 0x68, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x0a,
60 0x00, 0x00, 0x66, 0xc0, 0x10, 0x00, 0x02, 0x00, 0x01, 0x00, 0x01, 0x51, 0x80, 0x00, 0x05, 0x02,
61 0x6e, 0x73, 0xc0, 0x10, 0xc0, 0x6f, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x51, 0x80, 0x00, 0x04,
62 0xc0, 0xa8, 0x00, 0x17
65 // This uDNS message is a canned response that was originally captured by wireshark, then modified to match above (other than Addr order).
66 uint8_t test_order_response2_msgbuf[228] = {
67 0x0f, 0x98, // transaction id
69 0x00, 0x01, // 1 query: web.mydomain.test: type A, class IN
70 0x00, 0x04, // 4 anwsers: Addr 10.0.0.102, Addr 10.0.0.101, Addr 10.0.0.104, Addr 10.0.0.105
71 0x00, 0x01, // 1 authoritative nameservers: mydomain.test: type NS, class IN, ns ns.mydomain.test
72 0x00, 0x01, // 1 additional: ns.mydomain.test: type A, class IN, addr 192.168.0.23
73 0x03, 0x77, 0x65, 0x62,
74 0x08, 0x6d, 0x79, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x04, 0x74, 0x65, 0x73, 0x74, 0x00, 0x00,
75 0x01, 0x00, 0x01, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x0a,
76 0x00, 0x00, 0x66, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x0a,
77 0x00, 0x00, 0x65, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x0a,
78 0x00, 0x00, 0x68, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x0a,
79 0x00, 0x00, 0x69, 0xc0, 0x10, 0x00, 0x02, 0x00, 0x01, 0x00, 0x01, 0x51, 0x80, 0x00, 0x05, 0x02,
80 0x6e, 0x73, 0xc0, 0x10, 0xc0, 0x6f, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x51, 0x80, 0x00, 0x04,
81 0xc0, 0xa8, 0x00, 0x17
84 // Variables associated with contents of the above uDNS message
85 char test_order_domainname_cstr[] = "web.mydomain.test.";
87 @interface CacheOrderTest : XCTestCase
89 UDPSocket* local_socket;
90 request_state* client_request_message;}
93 @implementation CacheOrderTest
95 // The InitThisUnitTest() initializes the mDNSResponder environment as well as
96 // a DNSServer. It also allocates memory for a local_socket and client request.
97 // Note: This unit test does not send packets on the wire and it does not open sockets.
100 mDNSPlatformMemZero(&mDNSStorage, sizeof(mDNS));
102 // Init unit test environment and verify no error occurred.
103 mStatus result = init_mdns_environment(mDNStrue);
104 XCTAssertEqual(result, mStatus_NoError);
106 // Add one DNS server and verify it was added.
108 XCTAssertEqual(CountOfUnicastDNSServers(&mDNSStorage), 1);
110 // Create memory for a socket that is never used or opened.
111 local_socket = (UDPSocket *) mDNSPlatformMemAllocateClear(sizeof(*local_socket));
113 // Create memory for a request that is used to make this unit test's client request.
114 client_request_message = calloc(1, sizeof(request_state));
119 mDNS *m = &mDNSStorage;
120 request_state* req = client_request_message;
121 DNSServer *ptr, **p = &m->DNSServers;
125 reply_state *reply = req->replies;
126 req->replies = req->replies->next;
127 mDNSPlatformMemFree(reply);
129 mDNSPlatformMemFree(req);
131 mDNSPlatformMemFree(local_socket);
137 LogInfo("FinalizeUnitTest: Deleting server %p %#a:%d (%##s)", ptr, &ptr->addr, mDNSVal16(ptr->port), ptr->domain.c);
138 mDNSPlatformMemFree(ptr);
142 - (void)testSuspiciousReplyTestSeries
144 [self _clientQueryRequest];
145 [self _verifyCacheOrderBehavior];
148 // Simulate a uds client request by setting up a client request and then
149 // calling mDNSResponder's handle_client_request. The handle_client_request function
150 // processes the request and starts a query. This unit test verifies
151 // the client request and query were setup as expected. This unit test also calls
152 // mDNS_execute which determines the cache does not contain the new question's
154 - (void)_clientQueryRequest
156 mDNS *const m = &mDNSStorage;
157 request_state* req = client_request_message;
158 char *msgptr = (char *)test_order_query_msgbuf;
159 size_t msgsz = sizeof(test_order_query_msgbuf);
160 mDNSs32 min_size = sizeof(DNSServiceFlags) + sizeof(mDNSu32) + 4;
162 mStatus err = mStatus_NoError;
163 char qname_cstr[MAX_ESCAPED_DOMAIN_NAME];
165 // Process the unit test's client request
166 start_client_request(req, msgptr, msgsz, query_request, local_socket);
167 XCTAssertEqual(err, mStatus_NoError);
169 // Verify the request fields were set as expected
170 XCTAssertNil((__bridge id)req->next);
171 XCTAssertNil((__bridge id)req->primary);
172 XCTAssertEqual(req->sd, client_req_sd);
173 XCTAssertEqual(req->process_id, client_req_process_id);
174 XCTAssertFalse(strcmp(req->pid_name, client_req_pid_name));
175 XCTAssertEqual(req->validUUID, mDNSfalse);
176 XCTAssertEqual(req->errsd, 0);
177 XCTAssertEqual(req->uid, client_req_uid);
178 XCTAssertEqual(req->ts, t_complete);
179 XCTAssertGreaterThan((mDNSs32)req->data_bytes, min_size);
180 XCTAssertEqual(req->msgend, msgptr+msgsz);
181 XCTAssertNil((__bridge id)(void*)req->msgbuf);
182 XCTAssertEqual(req->hdr.version, VERSION);
183 XCTAssertNil((__bridge id)req->replies);
184 XCTAssertNotEqual(req->terminate, (req_termination_fn)0);
185 XCTAssertEqual(req->flags, kDNSServiceFlagsReturnIntermediates);
186 XCTAssertEqual(req->interfaceIndex, kDNSServiceInterfaceIndexAny);
188 // Verify the query fields were set as expected
189 q = &req->u.queryrecord.op.q;
190 XCTAssertNotEqual(q, (DNSQuestion *)mDNSNULL);
191 XCTAssertEqual(q, m->Questions);
192 XCTAssertEqual(q, m->NewQuestions);
193 XCTAssertEqual(q->SuppressUnusable, mDNSfalse);
194 XCTAssertEqual(q->ReturnIntermed, mDNStrue);
195 XCTAssertEqual(q->Suppressed, mDNSfalse);
197 ConvertDomainNameToCString(&q->qname, qname_cstr);
198 XCTAssertFalse(strcmp(qname_cstr, test_order_domainname_cstr));
199 XCTAssertEqual(q->qnamehash, DomainNameHashValue(&q->qname));
201 XCTAssertEqual(q->InterfaceID, mDNSInterface_Any);
202 XCTAssertEqual(q->flags, req->flags);
203 XCTAssertEqual(q->qtype, 1);
204 XCTAssertEqual(q->qclass, 1);
205 XCTAssertEqual(q->LongLived, 0);
206 XCTAssertEqual(q->ExpectUnique, mDNSfalse);
207 XCTAssertEqual(q->ForceMCast, 0);
208 XCTAssertEqual(q->TimeoutQuestion, 0);
209 XCTAssertEqual(q->WakeOnResolve, 0);
210 XCTAssertEqual(q->UseBackgroundTraffic, 0);
211 XCTAssertEqual(q->ValidationRequired, 0);
212 XCTAssertEqual(q->ValidatingResponse, 0);
213 XCTAssertEqual(q->ProxyQuestion, 0);
214 XCTAssertNotEqual((void*)q->QuestionCallback, (void*)mDNSNULL);
215 XCTAssertNil((__bridge id)q->DNSSECAuthInfo);
216 XCTAssertNil((__bridge id)(void*)q->DAIFreeCallback);
217 XCTAssertEqual(q->AppendSearchDomains, 0);
218 XCTAssertNil((__bridge id)q->DuplicateOf);
220 // Call mDNS_Execute to see if the new question, q, has an answer in the cache.
221 // It won't be yet because the cache is empty.
222 m->NextScheduledEvent = mDNS_TimeNow_NoLock(m);
225 // Verify mDNS_Execute processed the new question.
226 XCTAssertNil((__bridge id)m->NewQuestions);
228 // Verify the cache is empty and the request got no reply.
229 XCTAssertEqual(m->rrcache_totalused, 0);
230 XCTAssertNil((__bridge id)req->replies);
233 // This unit test performs two queries and verifies the cache oredr is updated on a new response.
234 // 1) Verify response is ordered in the cache as expected
235 // 2) Test again with new response, and verify cache order is updated
236 - (void)_verifyCacheOrderBehavior
238 mDNS *const m = &mDNSStorage;
241 request_state* req = client_request_message;
242 DNSQuestion *q = &req->u.queryrecord.op.q;
246 // Process first response
247 // Verify response cache count & order
249 msgptr = (DNSMessage *)test_order_response1_msgbuf;
250 msgsz = sizeof(test_order_response1_msgbuf);
251 receive_response(req, msgptr, msgsz);
253 // Verify records received
254 mDNSu32 CacheUsed =0, notUsed =0;
255 LogCacheRecords_ut(mDNS_TimeNow(m), &CacheUsed, ¬Used);
256 XCTAssertEqual(CacheUsed, 5); // Verify 4 records received + Cache Group
258 // Verify record order
259 mDNSu8 lastoctet1[4] = {101, 105, 104, 102};
260 status = verify_cache_addr_order_for_domain_ut(m, lastoctet1, 4, &q->qname);
261 XCTAssertEqual(status, mStatus_NoError, @"Cache order test 1 failed");
264 // Process second response
265 // Verify response cache count & order
267 msgptr = (DNSMessage *)test_order_response2_msgbuf;
268 msgsz = sizeof(test_order_response2_msgbuf);
269 receive_response(req, msgptr, msgsz);
271 // Verify records received
272 LogCacheRecords_ut(mDNS_TimeNow(m), &CacheUsed, ¬Used);
273 XCTAssertEqual(CacheUsed, 5); // Verify 4 records received + Cache Group
275 // Verify record order
276 mDNSu8 lastoctet2[4] = {102, 101, 104, 105};
277 status = verify_cache_addr_order_for_domain_ut(m, lastoctet2, 4, &q->qname);
278 XCTAssertEqual(status, mStatus_NoError, @"Cache order test 2 failed");